package com.gitee.fastmybatis.core.support;

import com.gitee.fastmybatis.core.EqualColumn;
import com.gitee.fastmybatis.core.FastmybatisContext;
import com.gitee.fastmybatis.core.PageInfo;
import com.gitee.fastmybatis.core.PageResult;
import com.gitee.fastmybatis.core.ext.MapperRunner;
import com.gitee.fastmybatis.core.mapper.BaseMapper;
import com.gitee.fastmybatis.core.mapper.OneResult;
import com.gitee.fastmybatis.core.mapper.SearchMapper;
import com.gitee.fastmybatis.core.query.LambdaQuery;
import com.gitee.fastmybatis.core.query.Query;
import com.gitee.fastmybatis.core.util.ClassUtil;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * 通用service接口<br>
 * 使用方式：
 * <pre>
 * <code>
 * {@literal
 * @Service
 * public class UserService implements LambdaService<TUser, Integer, TUserMapper> {
 *
 * }
 * }
 * </code>
 * </pre>
 *
 * @param <E>      实体类，如：Student
 * @param <Mapper> Mapper类，如：TUserMapper
 * @author thc
 * @since 2.12.2
 */
public interface LambdaService<E, Mapper extends BaseMapper<E>> {
    default Mapper getMapper() {
        return getMapperRunner().getMapper();
    }

    default Class<E> getEntityClass() {
        return (Class<E>) ClassUtil.getSuperInterfaceGenericTypeCache(getClass(), 0);
    }

    default MapperRunner<Mapper> getMapperRunner() {
        return FastmybatisContext.getCrudMapperRunner(getEntityClass());
    }

    /**
     * 创建一个LambdaUpdateQuery
     *
     * @return 返回LambdaUpdateQuery
     */
    default LambdaQuery<E> query() {
        return Query.create(getEntityClass());
    }

    // region 新增

    /**
     * 保存，忽略null字段
     *
     * @param entity 实体类
     * @return 受影响行数
     */
    default int save(E entity) {
        Objects.requireNonNull(entity);
        return getMapperRunner().run(mapper -> mapper.saveIgnoreNull(entity));
    }


    /**
     * 保存或修改，忽略null字段，当数据库存在记录执行UPDATE，否则执行INSERT
     *
     * @param entity 实体类
     * @return 受影响行数
     */
    default int saveOrUpdate(E entity) {
        return getMapperRunner().run(mapper -> mapper.saveOrUpdateIgnoreNull(entity));
    }

    /**
     * 保存或修改，忽略null字段，当数据库存在记录执行UPDATE，否则执行INSERT
     *
     * @param entity 实体类
     * @return 受影响行数
     */
    default int saveOrUpdateIgnoreNull(E entity) {
        return getMapperRunner().run(mapper -> mapper.saveOrUpdateIgnoreNull(entity, this::checkExist));
    }

    /**
     * 保存或修改，忽略null字段，当数据库存在记录执行UPDATE，否则执行INSERT
     *
     * @param entity       实体类
     * @param existChecker 检查是否存在，存在返回true，将执行UPDATE；不存在返回false，将执行INSERT
     * @return 受影响行数
     */
    default int saveOrUpdateIgnoreNull(E entity, Function<E, Boolean> existChecker) {
        return getMapperRunner().run(mapper -> mapper.saveOrUpdateIgnoreNull(entity, existChecker));
    }


    /**
     * 批量保存，忽略null字段<br>
     *
     * @param entitys 实体类集合
     * @return 受影响行数
     */
    default int saveBatch(Collection<E> entitys) {
        if (entitys == null || entitys.isEmpty()) {
            return 0;
        }
        return getMapperRunner().run(mapper -> mapper.saveBatchIgnoreNull(entitys));
    }

    /**
     * 分批次保存，忽略null字段<br>
     * <pre>
     * <code>saveBatch(records, 500)</code>
     * 分批次保存，每次保存500条
     * </pre>
     * <pre>
     * 获取保存后的自增主键id值：<code>Integer id = entity.getId();</code>
     * </pre>
     *
     * @param records       实体类集合
     * @param partitionSize 每次保存行数
     * @return 返回保存成功行数
     */
    default int saveBatch(Collection<E> records, int partitionSize) {
        if (records == null || records.isEmpty()) {
            return 0;
        }
        return getMapperRunner().run(mapper -> mapper.saveBatchIgnoreNull(records, partitionSize));
    }


    // endregion

    // region 修改

    /**
     * 更新，忽略null字段
     *
     * @param entity 实体类
     * @return 受影响行数
     */
    default int update(E entity) {
        Objects.requireNonNull(entity);
        return getMapperRunner().run(mapper -> mapper.updateIgnoreNull(entity));
    }


    /**
     * 根据条件更新部分字段(Lambda)
     * <pre>
     * {@literal
     * LambdaQuery<TUser> updateQuery = Query.lambdaUpdate(TUser.class);
     * updateQuery.set(TUser::getUsername, "王五");
     * updateQuery.eq(TUser::getId, 6);
     * service.update(updateQuery);
     * }
     * 对应SQL：UPDATE `t_user` SET username = ?  WHERE id = ?
     * </pre>
     *
     * @param updateQuery 更新条件
     * @return 返回影响行数
     */
    default int update(LambdaQuery<E> updateQuery) {
        return getMapperRunner().run(mapper -> mapper.update(updateQuery));
    }

    // endregion

    // region 删除

    /**
     * 删除记录（底层根据id删除），在有逻辑删除字段的情况下，做UPDATE操作。
     *
     * @param entity 实体类
     * @return 受影响行数
     */
    default int delete(E entity) {
        Objects.requireNonNull(entity);
        return getMapperRunner().run(mapper -> mapper.delete(entity));
    }

    /**
     * 根据id删除，在有逻辑删除字段的情况下，做UPDATE操作
     *
     * @param id 主键id值
     * @return 受影响行数
     */
    default int deleteById(Serializable id) {
        Objects.requireNonNull(id);
        return getMapperRunner().run(mapper -> mapper.deleteById(id));
    }

    /**
     * 根据指定字段值删除，在有逻辑删除字段的情况下，做UPDATE操作<br>
     * <pre>
     * 根据数组删除
     * {@literal mapper.deleteByColumn(TUser::getUsername, Arrays.asList("jim", "tom")); }
     * 对应SQL:DELETE FROM table WHERE username in ('jim', 'tom')
     *
     * 根据某个值删除
     * {@literal mapper.deleteByColumn(TUser::getUsername, "jim"); }
     * 对应SQL:DELETE FROM table WHERE username = 'jim'
     * </pre>
     *
     * @param column       数据库字段名
     * @param value        条件值，可以是单值String，int，也可以是集合List，Collection
     * @param equalColumns equalColumns 如果是UPDATE逻辑删除，则指定set部分，用来更新其它字段
     * @return 返回影响行数
     */
    default int deleteByColumn(Getter<E, ?> column, Object value, EqualColumn... equalColumns) {
        Objects.requireNonNull(value);
        return getMapperRunner().run(mapper -> mapper.deleteByColumn(column, value, equalColumns));
    }

    /**
     * 根据条件删除，在有逻辑删除字段的情况下，做UPDATE操作<br>
     * <pre>
     * {@literal
     * Query query = Query.create();
     * query.eq("state", 3);
     * int i = service.deleteByQuery(query);
     * }
     * 对应SQL:
     * DELETE FROM `t_user` WHERE state = 3
     * </pre>
     *
     * @param query        查询对象
     * @param equalColumns 如果是UPDATE逻辑删除，则指定set部分，用来更新其它字段
     * @return 受影响行数
     */
    default int deleteByQuery(Query query, EqualColumn... equalColumns) {
        Objects.requireNonNull(query);
        return getMapperRunner().run(mapper -> mapper.deleteByQuery(query));
    }

    /**
     * 根据条件删除，在有逻辑删除字段的情况下，做UPDATE操作<br>
     * <pre>
     * {@literal
     * Query query = Query.lambdaUpdate(TUser.class)
     *  .set(TUser::getRemark, "被xx删除")
     *  .eq(TUser::getId, 3);
     * int i = service.deleteByQuery(query);
     * }
     * 对应SQL:
     * UPDATE `t_user` SET is_del=1, remark='被xx删除' WHERE id = 3 AND is_del=0
     * </pre>
     *
     * @param query 查询对象
     * @return 受影响行数
     */
    default int deleteByQuery(LambdaQuery<E> query) {
        return getMapperRunner().run(mapper -> mapper.deleteByQuery(query));
    }

    /**
     * 根据多个主键id删除，在有逻辑删除字段的情况下，做UPDATE操作
     *
     * @param ids 主键id
     * @return 返回影响行数
     */
    default int deleteByIds(Collection<? extends Serializable> ids) {
        return getMapperRunner().run(mapper -> mapper.deleteByIds(ids));
    }

    /**
     * 强制删除（底层根据id删除），忽略逻辑删除字段，执行DELETE语句
     *
     * @param entity 实体类
     * @return 受影响行数
     */
    default int forceDelete(E entity) {
        Objects.requireNonNull(entity);
        return getMapperRunner().run(mapper -> mapper.forceDelete(entity));
    }

    /**
     * 根据id强制删除，忽略逻辑删除字段，执行DELETE语句
     *
     * @param id 主键id值
     * @return 受影响行数
     */
    default int forceDeleteById(Serializable id) {
        Objects.requireNonNull(id);
        return getMapperRunner().run(mapper -> mapper.forceDeleteById(id));
    }

    /**
     * 根据条件强制删除，忽略逻辑删除字段，执行DELETE语句
     *
     * @param query 查询对象
     * @return 受影响行数
     */
    default int forceDeleteByQuery(Query query) {
        return getMapperRunner().run(mapper -> mapper.forceDeleteByQuery(query));
    }

    // endregion

    // region 查询

    /**
     * 根据条件查询所有记录<br>
     * <pre>
     * {@literal
     * Query query = Query.create()
     *         .eq("state", 0)
     *         .in("money", Arrays.asList(100, 1.0, 3));
     * List<TUser> list = service.list(query);
     * }
     * 对应SQL:
     * SELECT col1, col2, ...
     * FROM `t_user` t
     * WHERE state = ? AND money IN ( ? , ? , ? )
     * </pre>
     *
     * @param query 查询条件
     * @return 返回实体对象集合，没有返回空集合
     */
    default List<E> list(Query query) {
        return getMapperRunner().run(mapper -> mapper.list(query));
    }

    /**
     * 根据字段查询所有记录<br>
     *
     * <pre>
     * {@literal
     * List<TUser> list = service.listByField(TUser::getAge, 20);
     * }
     * </pre>
     * 对应SQL:
     * <code>
     * SELECT col1, col2, ... FROM t_user WHERE age = 20;
     * </code>
     *
     * @param column 字段
     * @param value  字段值,可以是单值也可以是集合，Number/String/Boolean/Collection/Array
     * @return 返回实体对象集合，没有返回空集合
     */
    default List<E> listByField(Getter<E, ?> column, Object value) {
        return getMapperRunner().run(mapper -> mapper.listByField(column, value));
    }

    /**
     * 查询全部数据
     *
     * @return 返回全部数据，没有返回空list
     */
    default List<E> listAll() {
        return getMapperRunner().run(SearchMapper::listAll);
    }

    /**
     * 查询全部数据,指定返回字段
     * <pre>
     * {@literal
     * List<TUser> users = service.listAll(TUser::getId, TUser::getUsername);
     *
     * 对应SQL:SELECT id, username FROM t_user;
     * }
     * </pre>
     *
     * @param columns 指定返回字段
     * @return 返回全部数据，没有返回空list
     */
    default List<E> listAll(Getter<E, ?>... columns) {
        LambdaQuery<E> query = Query.create(getEntityClass())
                .select(columns);
        return list(query);
    }

    /**
     * 查询返回Map，Map里面key对应数据库字段名/别名，value对应值
     * <pre>
     * {@literal
     * List<Map<String, Object>> listMap = service.listMap( query);
     * }
     * </pre>
     *
     * @param query 查询条件
     * @return 返回结果集，没有则返回空list
     */
    default List<Map<String, Object>> listMap(Query query) {
        return getMapperRunner().run(mapper -> mapper.listMap(query));
    }

    /**
     * list查询并转换结果
     * <p>
     *     <b>注:仅此方法支持group by查询</b>
     * </p>
     * <pre>
     * {@literal
     * Query query = Query.query(TUser.class)
     *          .select("state, count(*) as cnt")
     *         .eq(TUser::getId, 3)
     *         .gt(TUser::getMoney, 1)
     *         .groupBy("state");
     * List<GroupVO> groupList = mapper.list(query, GroupVO.class);
     *
     * @Data
     * public class GroupVO {
     *     private Integer state;
     *     private Long cnt;
     * }
     * }
     * </pre>
     * @param query 查询条件
     * @param clazz 待转换的class
     * @return 返回结果
     * @param <V> 类型
     */
    default <V> List<V> list(Query query, Class<V> clazz) {
        return getMapperRunner().run(mapper -> mapper.list(query, clazz));
    }

    /**
     * 返回基本类型值
     * {@literal
     * Query query = Query.create()
     *                 .select("sum(money)")
     *                 .gt("id", 1);
     * BigDecimal value = userMapper.getPrimitive(query, BigDecimal.class).getOrThrow();
     * }
     * @param query 查询条件
     * @param clazz 基本类型值,如:Integer.class, BigDecimal.class, Date.class,类型不对将抛出IllegalArgumentException异常
     * @return 返回OneResult
     * @param <V> 类型
     */
    default <V> OneResult<V> getPrimitive(Query query, Class<V> clazz) {
        return getMapperRunner().run(mapper -> mapper.getPrimitive(query, clazz));
    }

    /**
     * 根据条件查找单条记录<br>
     * <pre>
     * {@literal
     * // 查询id=3,金额大于1的用户
     * Query query = Query.create()
     *         .eq("id", 3)
     *         .gt("money", 1);
     * TUser user = service.get(query);
     * }
     * 对应SQL:
     * SELECT col1, col2, ...
     * FROM `t_user` t
     * WHERE id = ? AND money > ? LIMIT 1
     * </pre>
     *
     * @param query 查询条件
     * @return 返回实体对象，没有返回null
     */
    default E get(Query query) {
        return getMapperRunner().run(mapper -> mapper.get(query));
    }

    /**
     * 根据条件查找单条记录<br>
     * <pre>
     * {@literal
     * // 查询id=3,金额大于1的用户
     * Query query = Query.query(TUser.class)
     *         .eq(TUser::getId, 3)
     *         .gt(TUser::getMoney, 1);
     * Optional<TUser> userOpt = service.getOptional(query);
     * }
     * 对应SQL:
     * SELECT col1, col2, ...
     * FROM `t_user` t
     * WHERE id = ? AND money > ? LIMIT 1
     * </pre>
     *
     * @param query 查询条件
     * @return 返回Optional对象
     */
    default Optional<E> getOptional(Query query) {
        return getMapperRunner().run(mapper -> mapper.getOptional(query));
    }

    /**
     * 查询一条记录,不会追加limit 1
     *
     * @param query 查询条件
     * @return 返回包装结果
     */
    default OneResult<E> getOne(Query query) {
        return getMapperRunner().run(mapper -> mapper.getOne(query));
    }

    /**
     * 查询一条记录
     *
     * @param query          查询条件
     * @param appendLimitOne 是否追加limit 1,如果true，始终返回1条数据
     * @return 返回包装结果
     */
    default OneResult<E> getOne(Query query, boolean appendLimitOne) {
        return getMapperRunner().run(mapper -> mapper.getOne(query, appendLimitOne));
    }

    /**
     * 根据字段查询一条记录, 只返回一条, 末尾加limit 1<br>
     * 如果要判断多条，参考 {@link #getOneByField }
     * <pre>
     * {@literal
     * TUser user = service.get(TUser::getUsername, "王五");
     * }
     * </pre>
     * <code>
     * SELECT col1,col2,... FROM table WHERE {column} = {value} LIMIT 1
     * </code>
     *
     * @param column 数据库字段名
     * @param value  字段值
     * @return 返回实体对象，没有返回null
     * @see #getOneByField(Getter, Object)
     */
    default E getByField(Getter<E, ?> column, Object value) {
        return getMapperRunner().run(mapper -> mapper.getByField(column, value));
    }

    /**
     * 根据字段查询一条记录, 返回OneResult<br>
     * <pre>
     * {@literal
     * OneResult user = mapper.getOneByField(TUser::getUsername, "王五");
     * }
     * </pre>
     * <code>
     * SELECT col1,col2,... FROM table WHERE {column} = {value} LIMIT 1
     * </code>
     *
     * @param column 数据库字段名
     * @param value  字段值
     * @return 返回实OneResult
     */
    default OneResult<E> getOneByField(Getter<E, ?> column, Object value) {
        return getMapperRunner().run(mapper -> mapper.getOneByField(column, value));
    }

    /**
     * 查询总记录数<br>
     * <pre>
     * {@literal
     * Query query = Query.create();
     * // 添加查询条件
     * query.eq("state", 0);
     * // 获取总数
     * long total = service.getCount(query);
     *
     * 对应SQL:
     * SELECT COUNT(*) FROM t_user WHERE `state` = 0
     * }
     * </pre>
     *
     * @param query 查询条件
     * @return 返回总记录数
     */
    default long getCount(Query query) {
        return getMapperRunner().run(mapper -> mapper.getCount(query));
    }

    /**
     * 查询单条数据返回指定字段并转换到指定类中<br>
     * <pre>
     * {@literal
     * Query query = Query.create().eq("id", 6);
     * UserVO userVo = service.get(query, UserVO.class);
     * }
     * 对应SQL:
     * SELECT id , username FROM `t_user` t WHERE id = 6 AND LIMIT 0,1
     * </pre>
     *
     * @param query 查询条件
     * @param clazz 待转换的类，类中的字段类型必须跟实体类的中类型一致
     * @param <T>   转换类类型
     * @return 返回转换类，查不到返回null
     */
    default <T> T get(Query query, Class<T> clazz) {
        return getMapperRunner().run(mapper -> mapper.get(query, clazz));
    }

    /**
     * 查询单条数据返回指定字段并转换到指定类中<br>
     * <pre>
     * {@literal
     * Query query = Query.create().eq("id", 6);
     * UserDTO userDTO = service.get(query, user -> {
     *     UserDTO userDTO = new UserDTO();
     *
     *     return userDTO;
     * });
     * }
     * 对应SQL:
     * SELECT id , username FROM `t_user` t WHERE id = 6 AND LIMIT 0,1
     * </pre>
     *
     * @param query     查询条件
     * @param converter 转换器
     * @param <T>       转换类类型
     * @return 返回转换类，查不到返回null
     */
    default <T> T get(Query query, Function<E, T> converter) {
        return getMapperRunner().run(mapper -> mapper.get(query, converter));
    }

    /**
     * 查询某一行某个字段值<br>
     * <pre>
     * {@literal
     * Query query = Query.create().eq("id", 6);
     * String username = service.get(query, TUser::getUsername);
     * }
     * 转换成SQL：
     * SELECT username FROM `t_user` t WHERE id = 6 LIMIT 0,1
     * </pre>
     *
     * @param query  查询条件
     * @param column 数据库字段
     * @return 返回单值，查不到返回null
     */
    default <R> R getValue(Query query, Getter<E, R> column) {
        return getMapperRunner().run(mapper -> mapper.getValue(query, column));
    }

    /**
     * 查询某一行某个字段值<br>
     * <pre>
     * {@literal
     * Query query = Query.query(TUser.class).eq(TUser::getId, 6);
     * String username = service.getValueOptional(query, TUser::getUsername).orElse("");
     * }
     * 转换成SQL：
     * SELECT username FROM `t_user` t WHERE id = 6 LIMIT 0,1
     * </pre>
     *
     * @param query  查询条件
     * @param column 数据库字段
     * @return 返回Optional
     */
    default <R> Optional<R> getValueOptional(Query query, Getter<E, R> column) {
        return getMapperRunner().run(mapper -> mapper.getValueOptional(query, column));
    }

    /**
     * 根据主键查询<br>
     * <pre>
     * {@literal
     * TUser user = service.getById(3);
     * }
     * 对应SQL:
     * SELECT col1, col2, ...
     * FROM `t_user` t
     * WHERE id = 3
     * </pre>
     *
     * @param id 主键值
     * @return 返回实体对象，没有返回null
     */
    default E getById(Serializable id) {
        return getMapperRunner().run(mapper -> mapper.getById(id));
    }

    /**
     * 根据主键查询强制查询，忽略逻辑删除字段<br>
     * <pre>
     * {@literal
     * TUser user = service.forceById(3);
     * }
     * 对应SQL:
     * SELECT col1, col2, ...
     * FROM `t_user` t
     * WHERE id = 3
     * </pre>
     *
     * @param id 主键值
     * @return 返回实体对象，没有返回null
     */
    default E forceGetById(Serializable id) {
        return getMapperRunner().run(mapper -> mapper.forceGetById(id));
    }


    /**
     * 根据多个主键查询<br>
     * <pre>
     * {@literal
     * List<User> list = service.listByIds(Arrays.asList(1,2,3));
     * }
     * </pre>
     * <code>
     * SELECT col1, col2, ... FROM table WHERE id in (val1, val2, ...)
     * </code>
     *
     * @param ids id集合
     * @return 返回结果集，没有返回空list
     */
    default List<E> listByIds(Collection<? extends Serializable> ids) {
        return getMapperRunner().run(mapper -> mapper.listByIds(ids));
    }

    /**
     * 查询某一列的值
     * <pre>
     * {@literal
     * List<String> usernameList = service.list(query, TUser::getUsername);
     *
     * 对应SQL：SELECT username FROM t_user WHERE ...
     * }
     * </pre>
     *
     * @param query  查询条件
     * @param column 返回某一列
     * @param <R>    列类型
     * @return 返回某一列数据，没有返回空list
     */
    default <R> List<R> listValue(Query query, Getter<E, R> column) {
        return getMapperRunner().run(mapper -> mapper.listValue(query, column));
    }

    /**
     * 分页查询，并转换结果
     * <pre>
     * {@literal
     * PageInfo<TUser> users = service.page(query, PageInfo.class);
     * }
     * </pre>
     *
     * @param query      查询条件
     * @param pageResult pageResult
     * @return 返回分页信息
     */
    default <P extends PageResult<E>> P page(Query query, Supplier<P> pageResult) {
        return getMapperRunner().run(mapper -> mapper.page(query, pageResult));
    }

    /**
     * 分页查询<br>
     * <pre>
     * {@literal
     * Query query = Query.create();
     * // 添加查询条件
     * query.eq("username", "张三")
     *         .page(1, 2) // 分页查询，按页码分，通常使用这种。
     * ;
     *
     * // 分页信息
     * PageInfo<TUser> pageInfo = service.page(query);
     *
     * List<TUser> list = pageInfo.getList(); // 结果集
     * long total = pageInfo.getTotal(); // 总记录数
     * int pageCount = pageInfo.getPageCount(); // 共几页
     * }
     * </pre>
     *
     * @param query 查询条件
     * @return 返回分页信息
     */
    default PageInfo<E> page(Query query) {
        return getMapperRunner().run(mapper -> mapper.page(query));
    }

    /**
     * 查询结果集，并转换结果集中的记录，转换处理每一行<br>
     * <pre>
     * {@literal
     *  PageInfo<TUser> pageInfo = service.page(query, tUser -> {
     *      // 对每行数据进行转换
     *      String username = tUser.getUsername();
     *      if ("张三".equals(username)) {
     *          tUser.setUsername("法外狂徒");
     *      }
     *      return tUser;
     *   });
     * }
     * 或者：
     * {@literal
     *  // 对结果集进行手动转换，如果仅仅是属性拷贝可以直接：mapper.page(query, UserVO::new);
     *  PageInfo<UserVO> page = service.page(query, user -> {
     *      UserVO userVO = new UserVO();
     *      BeanUtils.copyProperties(user, userVO);
     *      return userVO;
     *   });
     * }
     * </pre>
     *
     * @param query     查询条件
     * @param converter 转换类
     * @return 返回分页信息
     */
    default <R> PageInfo<R> page(Query query, Function<E, R> converter) {
        return getMapperRunner().run(mapper -> mapper.page(query, converter));
    }

    /**
     * 查询结果集，并转换结果集中的记录，转换处理list<br>
     * <pre>
     * {@literal
     * Query query = Query.create()
     *         .eq("state", 0);
     * PageInfo<UserVO> pageInfo = service.pageAndConvert(query, list -> {
     *     List<UserVO> retList = new ArrayList<>(list.size());
     *     for (TUser tUser : list) {
     *         UserVO userVO = new UserVO();
     *         BeanUtils.copyProperties(tUser, userVO);
     *         retList.add(userVO);
     *     }
     *     return retList;
     * });
     * }
     * </pre>
     *
     * @param query     查询条件
     * @param converter 转换类
     * @return 返回分页信息
     * @since 1.10.11
     */
    default <R> PageInfo<R> pageAndConvert(Query query, Function<List<E>, List<R>> converter) {
        return getMapperRunner().run(mapper -> mapper.pageAndConvert(query, converter));
    }

    /**
     * 查询结果集，并转换结果集中的记录，并对记录进行额外处理<br>
     * <pre>
     * {@literal
     *  PageInfo<UserVO> page = service.page(query, UserVO::new, userVO -> {
     *      System.out.println(userVO.getUsername());
     *  });
     * }
     * </pre>
     *
     * @param query  查询条件
     * @param target 转换后的类
     * @param format 对转换后的类格式化，此时的对象已经完成属性拷贝
     * @param <R>    结果集类型
     * @return 返回PageInfo对象
     */
    default <R> PageInfo<R> page(Query query, Supplier<R> target, Consumer<R> format) {
        return getMapperRunner().run(mapper -> mapper.page(query, target, format));
    }

    /**
     * 查询返回easyui结果集<br>
     * 如果前端使用easyui，此返回结果可适用于easyui的datagrid组件
     *
     * @param query 查询条件
     * @return 返回easyui分页信息
     */
    default PageEasyui<E> pageEasyui(Query query) {
        return getMapperRunner().run(mapper -> mapper.pageEasyui(query));
    }

    /**
     * 查询结果并转换成Map对象<br>
     * 通过list中的某一列（如主键id）当做key返回map对象<br>
     * 如果key重复则抛出异常
     * <pre>
     * {@literal
     * public class User {
     *     private Integer id;
     *     private String name;
     * }
     *
     * Query query = Query.create()
     *         .ge("id", 1);
     * // id -> TUser
     * Map<Integer, TUser> map = service.getMap(query, TUser::getId);
     * }
     * </pre>
     *
     * @param query     查询条件
     * @param keyGetter 指定map中的key，确保唯一性，一般使用主键id或唯一索引列
     * @param <K>       key类型
     * @return 返回map对象
     */
    default <K> Map<K, E> getMap(Query query, Function<E, K> keyGetter) {
        return getMapperRunner().run(mapper -> mapper.getMap(query, keyGetter));
    }

    /**
     * 查询结果并转换成Map对象<br>
     * 通过list中的某一列（如主键id）当做key返回map对象<br>
     * 如果key重复则抛出异常
     * <pre>
     * {@literal
     * // id -> TUser
     * Map<Integer, TUser> map = service.getMap(Arrays.asList(1,2,3), TUser::getId);
     * }
     * </pre>
     *
     * @param ids       主键id
     * @param keyGetter 指定map中的key，确保唯一性，一般使用主键id或唯一索引列
     * @param <K>       key类型
     * @return 返回map对象
     */
    default <K> Map<K, E> getMap(Collection<? extends Serializable> ids, Function<E, K> keyGetter) {
        String pkColumnName = FastmybatisContext.getPkColumnName(getEntityClass());
        Query query = Query.create().in(pkColumnName, ids);
        return getMapperRunner().run(mapper -> mapper.getMap(query, keyGetter));
    }

    /**
     * 查询结果并转换成Map对象<br>
     * 通过list中的某一列（如主键id）当做key返回map对象<br>
     * 如果key重复则抛出异常
     * <pre>
     * {@literal
     * public class User {
     *     private Integer id;
     *     private String name;
     * }
     *
     * List<User> -> Map<Integer, User> // 键:id, 值:当前对象
     * List<User> -> Map<Integer, String> // 键:id, 值:name字段
     * }
     * </pre>
     *
     * @param query       查询条件
     * @param keyGetter   指定map中的key，确保唯一性，一般使用主键id或唯一索引列
     * @param valueGetter 指定map中的值
     * @param <K>         key类型
     * @param <V>         value类型
     * @return 返回map对象
     */
    default <K, V> Map<K, V> getMap(Query query, Function<E, K> keyGetter, Function<E, V> valueGetter) {
        return getMapperRunner().run(mapper -> mapper.getMap(query, keyGetter, valueGetter));
    }

    /**
     * 查询结果并转换成Map对象<br>
     * 通过list中的某一列（如主键id）当做key返回map对象
     * <pre>
     * {@literal
     * public class User {
     *     private Integer id;
     *     private String name;
     * }
     *
     * List<User> -> Map<Integer, User> // 键:id, 值:当前对象
     * List<User> -> Map<Integer, String> // 键:id, 值:name字段
     * }
     * </pre>
     *
     * @param query         查询条件
     * @param keyGetter     指定map中的key，确保唯一性，一般使用主键id或唯一索引列
     * @param valueGetter   指定map中的值
     * @param mergeFunction key冲突返回哪个值
     * @param <K>           key类型
     * @param <V>           value类型
     * @return 返回map对象
     */
    default <K, V> Map<K, V> getMap(Query query, Function<E, K> keyGetter, Function<E, V> valueGetter, BinaryOperator<V> mergeFunction) {
        return getMapperRunner().run(mapper -> mapper.getMap(query, keyGetter, valueGetter, mergeFunction));
    }

    /**
     * 查询结果并转换成Map对象<br>
     * 通过list中的某一列（如主键id）当做key返回map对象
     * <pre>
     * {@literal
     * public class User {
     *     private Integer id;
     *     private String name;
     * }
     *
     * List<User> -> Map<Integer, User> // 键:id, 值:当前对象
     * List<User> -> Map<Integer, String> // 键:id, 值:name字段
     * }
     * </pre>
     *
     * @param query         查询条件
     * @param keyGetter     指定map中的key，确保唯一性，一般使用主键id或唯一索引列
     * @param valueGetter   指定map中的值
     * @param mergeFunction key冲突返回哪个值
     * @param mapSupplier   构造map
     * @param <K>           key类型
     * @param <V>           value类型
     * @param <M>           Map类型
     * @return 返回map对象
     */
    default <K, V, M extends Map<K, V>> M getMap(Query query,
                                                 Function<E, K> keyGetter,
                                                 Function<E, V> valueGetter,
                                                 BinaryOperator<V> mergeFunction,
                                                 Supplier<M> mapSupplier) {
        return getMapperRunner().run(mapper -> mapper.getMap(
                query, keyGetter, valueGetter, mergeFunction, mapSupplier
        ));
    }

    /**
     * 查询结果并分组
     * <pre>
     * {@literal
     * Map<Long, List<SysDictValueBO>> map = service.getMapGrouping(query, SysDictValue::getItemId, sysDictValue -> {
     *             return CopyUtil.copyBean(sysDictValue, SysDictValueBO::new);
     *         });
     * }
     * </pre>
     *
     * @param query       查询条件
     * @param keyGetter   分组key
     * @param valueGetter 值转换
     * @param <K>         key类型
     * @param <V>         value类型
     * @return 返回map
     */
    default <K, V> Map<K, List<V>> getMapGrouping(Query query, Function<E, K> keyGetter, Function<E, V> valueGetter) {
        return getMapperRunner().run(mapper -> mapper.getMapGrouping(
                query, keyGetter, valueGetter
        ));
    }

    /**
     * 查询结果并分组
     * <pre>
     * {@literal
     * Map<Long, List<SysDictValue>> map = service.getMapGrouping(query, SysDictValue::getItemId);
     * }
     * </pre>
     *
     * @param query     查询条件
     * @param keyGetter 分组key
     * @param <K>       key类型
     * @return 返回map
     */
    default <K> Map<K, List<E>> getMapGrouping(Query query, Function<E, K> keyGetter) {
        return getMapperRunner().run(mapper -> mapper.getMapGrouping(
                query, keyGetter
        ));
    }

    /**
     * 查询列表并将结果转换成树结构<br>
     * 实体类必须实现{@link TreeNode}接口
     * <pre>
     * {@literal
     * CREATE TABLE `menu` (
     *   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
     *   `name` varchar(64) NOT NULL COMMENT '菜单名称',
     *   `parent_id` int(11) NOT NULL DEFAULT '0' COMMENT '父节点',
     *   PRIMARY KEY (`id`)
     * ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='菜单表';
     *
     * 实体类
     *
     * public class Menu implements TreeNode<Menu, Integer> {
     *
     *     private Integer id;
     *     private String name;
     *     private Integer parentId;
     *     private List<Menu> children;
     *
     *     @Override
     *     public Integer takeId() {
     *         return getId();
     *     }
     *
     *     @Override
     *     public Integer takeParentId() {
     *         return getParentId();
     *     }
     *
     *     @Override
     *     public void setChildren(List<Menu> children) {
     *         this.children = children;
     *     }
     *
     *     getter setter...
     * }
     *
     * List<Menu> treeData = service.listTreeData(query, 0);
     *
     * }
     * </pre>
     *
     * @param query  查询条件
     * @param rootId 根节点id值，一般为0
     * @param <T>    节点类型，必须实现{@link TreeNode}接口
     * @return 返回树列表
     */
    default <T extends TreeNode<T, Serializable>> List<T> listTree(Query query, Serializable rootId) {
        return getMapperRunner().run(mapper -> mapper.listTree(query, rootId));
    }

    /**
     * 查询列表并将结果转换成树结构<br>
     * supplier返回的实体类必须实现{@link TreeNode}接口
     *
     * @param query    查询条件
     * @param rootId   根节点id值，一般为0
     * @param supplier 转换
     * @param <T>      节点类型，必须实现{@link TreeNode}接口
     * @return 返回树列表
     */
    default <T extends TreeNode<T, Serializable>> List<T> listTree(Query query, Serializable rootId, Supplier<T> supplier) {
        return getMapperRunner().run(mapper -> mapper.listTree(query, rootId, supplier));
    }

    /**
     * 查询列表并将结果转换成树结构<br>
     * Function转换的返回类必须实现{@link TreeNode}接口
     *
     * @param query  查询条件
     * @param rootId 根节点id值，一般为0
     * @param <T>    节点类型，必须实现{@link TreeNode}接口
     * @return 返回树列表
     */
    default <T extends TreeNode<T, Serializable>> List<T> listTree(Query query, Serializable rootId, Function<E, T> converter) {
        return getMapperRunner().run(mapper -> mapper.listTree(query, rootId, converter));
    }

    /**
     * 根据主键id检查记录是否存在<br>
     * <code>boolean exist = service.checkExist(user)</code>
     *
     * @param entity 实体类
     * @return 返回true，记录存在
     */
    default boolean checkExist(E entity) {
        return getMapperRunner().run(mapper -> mapper.checkExist(entity));
    }

    /**
     * 根据主键id检查记录是否存在<br>
     * <code>boolean exist = service.checkExistById(11)</code>
     *
     * @param id id值
     * @return 返回true，记录存在
     */
    default boolean checkExistById(Serializable id) {
        return getMapperRunner().run(mapper -> mapper.checkExistById(id));
    }


    /**
     * 根据某个字段检查记录是否存在
     * <pre>
     * boolean b = service.checkExist(TUser::getUsername, "jim");
     * </pre>
     *
     * @param getter 字段
     * @param value  值
     * @return 返回true，记录存在
     */
    default boolean checkExist(Getter<E, ?> getter, Object value) {
        return getMapperRunner().run(mapper -> mapper.checkExist(getter, value));
    }

    /**
     * 根据某个字段检查记录是否存在，且不是指定id的那条记录
     * <pre>
     * boolean b = service.checkExist(TUser:getUsername, "jim", 1)
     *
     * SELECT username FROM table WHERE username = ? and id != ?
     * </pre>
     *
     * @param getter 数据库字段名
     * @param value  值
     * @param id     需要排除的id值
     * @return 返回true，记录存在
     */
    default boolean checkExist(Getter<E, ?> getter, Object value, Serializable id) {
        return getMapperRunner().run(mapper -> mapper.checkExist(getter, value, id));
    }

    // endregion
}
